#来自selenium 导入web驱动
from selenium import webdriver
#来自 selenium.web驱动.support(支持)，导入 预期_条件 作为 EC
from selenium.webdriver.support import expected_conditions as EC
#导入时间
import time
#来自 selenium.web驱动.support(支持).select(选择)，导入 select(选择)
from selenium.webdriver.support.select import Select
#来自键盘，导入键盘 (文件下载弹窗处理)
from pykeyboard import PyKeyboard
#来自 selenium.web驱动.共同(常用).行动(动作).链 导入 操作链
from selenium.webdriver.common.action_chains import ActionChains
#；来自 selenium.web驱动.共同(常用).键 导入 键
from selenium.webdriver.common.keys import Keys
#导入外来文件
#from liulanqi.读取配置文件封装 import r
#建立一个类，把方法都封装到类里面，写脚本时，直接导入类，实例化后调用该方法
class SeleniumDriver1:
    #在构造方法中给对象定义一个变量，用来接收实例化的浏览器
    def __init__(self,browser):
        self.driver=self.open_browser(browser)

    #编写函数，封装实例化浏览器的方法
    def open_browser(self,browser):
        try:
            if browser=='chrome':
                driver=webdriver.Chrome()
            elif browser=='firefox':
                driver=webdriver.Firefox()
            elif browser=='ie':
                driver=webdriver.Ie()
            else:
                driver=webdriver.Edge()
            return driver
        except:#如果打开浏览器异常，给出提示,并且返回一个None给调用此方法的地方
            print('实例化浏览器失败')
            return None

    #封装访问网址的操作
    def get_url(self,url):
        #判断浏览器是否实例化成功，如果成功，则进行网址访问
        if self.driver!=None:
            self.driver.get(url)
        else:#如果浏览器实例化失败，则提示case失败
            print('case（用例）失败')

    #封装常见浏览器操作方法
    def handle_windows(self,*args):
        value=len(args)#计算数组的长度，即元素个数
        #如果个数为1，表示只掉用除了set之外的几个方法
        if value==1:
            #我们根据传入的参数值，判断执行哪个方法
            if args[0]=='max':
                self.driver.maximize_window()
            elif args[0]=='min':
                self.driver.minimize_window()
            elif args[0]=='back':
                self.driver.back()
            elif args[0]=='forward':
                self.driver.forward()
            elif args[0]=='refresh':
                self.driver.refresh()
            else:
                self.driver.quit()
        elif value==2:#如果参数个数为2则调用set方法设置浏览器大小
            self.driver.set_window_size(args[0],args[1])
        else:#否则提示错误信息
            print("您传入的参数有问题")

    #封装判断页面是否正确的代码
    def open_url_is_true(self,url,title_name=None):
        #首先打开网页
        self.get_url(url)
        #判断是否传入了标题
        if title_name!=None:
            #如果传入标题，则进行校验
            get_title=EC.title_contains(title_name)#实例化一个title_contains类的对象
            return get_title(self.driver)#在title_contains类的对象中传入浏览器对象，
            # 校验标题是否正确，并且将校验结果返回到调用函数的地方
        else:#如果没有传入标题，则给出错误提示
            print("您没有传入需要校验的标题")

    #封装窗口切换代码
    def switch_window(self,title_name=None):
        #获取所有窗口的句柄
        handl_list=self.driver.window_handles
        #获取当前窗口的句柄
        current_handle=self.driver.current_window_handle
        # 创建一个title_contains类的对象，用来传入需要校验的title标题
        title_a = EC.title_contains(title_name)
        #遍历所有的窗口
        for i in handl_list:
            if i != current_handle:#判断i是否为当前窗口的句柄，如果不是，则切换到句柄i所在的窗口
                self.driver.switch_to.window(i)
                time.sleep(3)
                a=title_a(self.driver)#对i窗口的标题进行校验，查看是否为目标窗口，
                if a==True:#判断校验结果，如果是，则跳出循环，不在切换窗口
                    break

    #封装定位单个元素的方法,传入两个参数，by表示定位元素的方法，value表示定位元素所有的属性值或者路径
    def get_element(self,by,value):
        #定义一个变量，用来接收定位到的元素，如果定位不到元素，则返回None
        element=None
        try:#
            if by=='id':
                element=self.driver.find_element_by_id(value)
            elif by=='name':
                element=self.driver.find_element_by_name(value)
            elif by=='class':
                element=self.driver.find_element_by_class_name(value)
            elif by=='css':
                element=self.driver.find_element_by_css_selector(value)
            elif by=='link':
                element=self.driver.find_element_by_partial_link_text(value)
            elif by=='xpath':
                element=self.driver.find_element_by_xpath(value)
            elif by=='tag':
                element=self.driver.find_element_by_tag_name(value)
            else:
                element=self.driver.find_element_by_xpath(value)
        except:
            print("定位方式",by,"定位值",value,"定位出现错误，没有定位成功")
        #调用方法判断定位到的元素是否可见，如果可见，将该元素返回到，调用函数的地方，否则返回False
        return self.element_isdisplay(element)

     #封装获取多个元素的方法
    def get_elements(self,by,value):
        #定义一个变量接收定位到的元素数组,如果没有定位到元素数组，则返回None
        elements=None
        #定义一个数组，用于接受可见元素
        element_list=[]
        if by == 'id':
            elements = self.driver.find_elements_by_id(value)
        elif by == 'name':
            elements = self.driver.find_elements_by_name(value)
        elif by == 'class':
            elements = self.driver.find_elements_by_class_name(value)
        elif by == 'css':
            elements = self.driver.find_elements_by_css_selector(value)
        elif by == 'link':
            elements = self.driver.find_elements_by_partial_link_text(value)
        elif by == 'tag':
            elements = self.driver.find_elements_by_tag_name(value)
        else:
            elements = self.driver.find_elements_by_xpath(value)
        #遍历所有的元素，
        for element in elements:
            #判断元素是否可见，如果不可见，使用continue跳出本次循环，进行下一次循环
            if self.element_isdisplay(element)==False:
                continue
            else:#否则将可见的元素添加到element_list数组中
                element_list.append(element)
        #将可见的元素列表返回到调用该方法的地方
        return element_list

    #对获取对应下标的元素方法进行封装
    def get_list_element(self,by,value,index):
        #设置一个变量接收get_elements函数定位到的元素数组
        elements=self.get_elements(by,value)
        #判断传入的index是否超过获取元素的长度
        if index>len(elements):#如果超长返回None，否则将对应下标的元素返回到调用函数的地方
            return None
        return elements[index]

    #封装输入操作
    def send_value(self,by,value,key):
        #定义变量来接受定位到的元素
        element=self.get_element(by,value)
        #对获取的元素进行判断，查看其是否可见
        if element==False:
            print("输入失败，定位元素没有展现出来")
        else:#如果元素可见，进行下一步操作
            #对定位的元素值进行判断，如果不为None，表示获取元素成功,可以对元素进行操作
            if element!=None:
                element.send_keys(key)
            else:
                print("输入失败，定位元素没有找到")

    #封装输入操作
    def click_element(self,by,value):
        #定义变量来接受定位到的元素
        element=self.get_element(by,value)
        #对获取的元素进行判断，查看其是否可见
        if element==False:
            print("点击失败，定位元素没有展现出来")
        else:#如果元素可见，进行下一步操作
            #对定位的元素值进行判断，如果不为None，表示获取元素成功,可以对元素进行操作
            if element!=None:
                element.click()
            else:
                print("点击失败，定位元素没有找到")

    #封装checkbox(复选)框操作方法
    def check_box_isselected(self,by,value,check):
        #定义一个变量获取定位到的复选框
        element=self.get_element(by,value)
        #对获取的元素进行判断，查看其是否可见
        if element==False:
            print("点击失败，定位元素没有展现出来")
        else:#如果元素可见，进行下一步操作
            #先判断一下复选框的默认状态,并把结果赋值给一个变量
            flag=element.is_selected()
            if flag==True:
                if check!='t':
                    #如果复选框默认选中，要求不选中，则点击一下，取消选中
                    self.click_element(by,value)
            else:
                if check=='t':
                    #如果复选框默认不选中，要求选中，则点击一下，选中复选框
                    self.click_element(by,value)

    #封装元素是否可见方法
    def element_isdisplay(self,element):
        #判断元素是否可见，并且将结果赋值给一个变量
        falg=element.is_displayed()
        #对结果进行判断，如果元素可见，将元素返回到调用函数的地方
        if falg==True:
            return element
        else:#如果元素不可见，则返回False
            return False

    # 封装下拉选项的方法，思路：传入info，index为父级下标，value_index为下一级下标
    # 传入这两个下标，调用Select选择下拉项
    def get_selected(self, info, value_index, index=None):
        # 实例化一个元素，初始值为None，用来接收定位到的父元素（下拉框）
        selected_element = None
        # 判断index是否优质，index非空才使用定位元素数组的方式定位父元素（下拉框）
        if index != None:
            # 通过get_list_element方法，根据下标，在数组中找到父元素（下拉框）
            selected_element = self.get_list_element(info,value_index, index)
        else:  # 如果index为None,表示程序只能定位到一个元素，使用get_element方法定位即可
            selected_element = self.get_element(info, value_index)
        # 调用Select中的select_by_index方法，通过下拉框的下标选择下拉选项
        Select(selected_element).select_by_index(value_index)

    #键盘录入，调用包from selenium.webdriver.common.keys import Keys
    def upload_file(self, file_name):
        # 实例化键盘对象
        pykey = PyKeyboard()
        # 切换输入法
        pykey.tap_key(pykey.shift_key)
        # 输入要上传文件的路径
        pykey.type_string(file_name)
        time.sleep(5)
        pykey.tap_key(pykey.enter_key)

    # 强制刷新 control+F5  导入包from selenium.webdriver.common.action_chains import ActionChains
    def F5(self):
        ActionChains(self.driver).key_down(Keys.CONTROL).key_down(Keys.F5).key_up(Keys.F5).perform()

    # 富文本操作
    def switch_iframe(self, info=None):
        iframe_element = self.get_element(info)
        if info != None:
            self.driver.switch_to.frame(iframe_element)
        else:
            self.driver.switch_to.default_content()

    # 封装滚动条操作
    def scroll_element(self, info):  # 传入info,查找对应的元素
        js = 'document.documentElement.scrollTop=10000'
        t = True
        while t:
            try:  # 使用try判断元素是否被查找到 ，如果查找到了，则t=False，否则抛出异常
                self.get_element(info)
                t = False
            except:  # 没有查找到元素，排除异常，执行代码滑动滚动条
                self.driver.execute_script(js)
    def ssss(self,info,title,shouji):
        js = 'document.documentElement.scrollTop=10000'
        t = True
        while t:
            # 获取所有手记元素
            element_list = self.driver.get_elements(info)
            # 建立一个for循环，遍历获取到的数组
            for element in element_list:
                # 获取手记对应的text内容
                course_name = element.find_element_by_tag_name(shouji).text
                # 判断手记内容是否与我们要查找的手记一致
                if course_name == title:
                    # 如果符合查找条件，点击控件
                    element.find_element_by_tag_name(shouji).click()
                    t = False
                    break
                if t:  # 如果t依然等于True表示没有通过for循环找到对应的手记，此时应该滑动滚动条
                    self.driver.execute_script(js)
                    time.sleep(5)

    # 原生和H5切换
    def ChangeWebview(self):
        '''切换到webview'''
        sleep(5)  # 此处加上睡眠等待，此时向服务器请求数据，一般数据量多时，会获取不到webview和native的界面元素
        d = self.tool.MyDriver()  # 调用appium中的driver，tool是用来引用driver
        list = d.contexts  # 将获取到的添加到集合list
        sleep(3)
        print(list)  # 打印查看

        for con in list:
            if con.lower().startswith('webview'):  # if判断若是以webview开头就切换
                sleep(2)
                d._switch_to.context(con)





